﻿using System;
using System.Drawing;
using System.Windows.Forms;
using GeoAzure.Core;
using GeoAzure.Core.Tests;

namespace GeoAzure.IndexVisualizer
{
    public partial class Form1 : Form
    {
        private readonly RTree<IBounded> _index;
        private Color[] _colors;
        private float _xScale;

        public Form1()
        {
            InitializeComponent();
            _index = new RTree<IBounded>();
            IBounded[] items = TestObjectFactory.CreatePointBoundedObjects(30000);
            for (int i = 0; i < items.Length; i++)
            {
                _index.InsertItem(items[i], items[i].Bounds);
            }

            _colors = new Color[10];
            _colors[0] = Color.Black;
            _colors[1] = Color.Magenta;
            _colors[2] = Color.Cyan;
            _colors[3] = Color.Red;
            _colors[4] = Color.Blue;
            _colors[5] = Color.Green;
            _colors[6] = Color.Lime;
        }

        private float XScale
        {
            get { return (float) ((drawPanel.ClientSize.Width - 1) / (2 * Math.PI)); }
        }

        private float YScale
        {
            get
            {
                return (float) -((drawPanel.ClientSize.Height - 1) / Math.PI);
            }
        }

        private void DrawNode(Graphics graphics, Pen pen, IndexEntry<IBounded> entry, int level)
        {
            if (level < minLevel.Value)
                return;
            if (level > 0)  // non-leaf node: we will recurse
            {
                Pen innerPen = new Pen(_colors[level], 1F / XScale);
                entry.Node.LockForReading();
                foreach (IndexEntry<IBounded> item in entry.Node.Entries)
                {
                    DrawNode(graphics, innerPen, item, level - 1);
                }
                entry.Node.ReleaseReadLock();
                innerPen.Dispose();

            }
            if (exclusive.Checked && level != minLevel.Value)
                return;
            GeoRectangle gr = entry.Bounds;
            RectangleF rect = new RectangleF((float) gr.BottomLeft.Longitude, (float) gr.BottomLeft.Latitude, (float) gr.Width, (float) gr.Height);
            if (level == -1)
            {
                graphics.DrawRectangle(pen, rect.X, rect.Y, rect.Width + 1F / XScale, rect.Height - 1F / YScale);
            }
            else
            {
                graphics.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
            }
        }

        private void minLevel_ValueChanged(object sender, EventArgs e)
        {
            drawPanel.Invalidate();
        }

        private void exclusive_CheckedChanged(object sender, EventArgs e)
        {
            drawPanel.Invalidate();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Location center = GeoAzure.Core.Location.FromDegrees(double.Parse(latitude.Text),
                                                                     double.Parse(longitude.Text));

            using (var graphics = GetGraphics())
            using (var pen = new Pen(Color.Red, 1F / XScale))
                foreach (var result in _index.QueryWithinDistance(center, double.Parse(distance.Text)))
                {
                    GeoRectangle gr = result.Bounds;
                    RectangleF rect = new RectangleF((float) gr.BottomLeft.Longitude, (float) gr.BottomLeft.Latitude, (float) gr.Width, (float) gr.Height);
                    graphics.DrawRectangle(pen, rect.X, rect.Y, rect.Width + 1F / XScale, rect.Height - 1F / YScale);

                }
        }

        private Graphics GetGraphics()
        {
            var g = drawPanel.CreateGraphics();

            g.ScaleTransform(XScale, YScale);
            g.TranslateTransform((float) Math.PI, -(float) (Math.PI / 2));

            return g;
        }

        private void drawPanel_Paint(object sender, PaintEventArgs e)
        {
            using (var g = GetGraphics())
            {

                using (Pen p = new Pen(_colors[_index.RootEntry.Node.Level + 1], 1F / XScale))
                    DrawNode(g, p, _index.RootEntry, _index.RootEntry.Node.Level);
            }

        }
    }
}
